package lt.vin.exaatto.server;

import java.security.Principal;

import lt.vin.exaatto.client.service.RpcService;
import lt.vin.exaatto.server.dao.ChatDao;
import lt.vin.exaatto.server.service.ChatService;
import lt.vin.exaatto.shared.Chat;
import lt.vin.exaatto.shared.ChatAlreadyExists;
import lt.vin.exaatto.shared.NoSuchChatException;
import lt.vin.exaatto.shared.NotOwnerException;
import lt.vin.exaatto.shared.UserInformation;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
 * The server side implementation of the RPC service.
 */
@Singleton
public class RpcServiceImpl extends RemoteServiceServlet implements RpcService {

	
	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 9102725961170634258L;
	
	@Inject ChatDao chatDao;
	
	@Inject ChatService chatService;

	/* (non-Javadoc)
	 * @see com.gcgt.client.GreetingService#getUserInformation()
	 */
	@Override
	public UserInformation getUserInformation() {
		UserInformation result = new UserInformation();
		
		Principal userPrincipal = getThreadLocalRequest().getUserPrincipal();
		UserService userService = UserServiceFactory.getUserService();		
		
		result.setLogoutUrl(userService.createLogoutURL("/"));
		result.setLoginUrl(userService.createLoginURL("/manage.html"));
		if (userPrincipal != null) {
			result.setUsername(userPrincipal.getName());
			result.setChats(getChatDao().getChats(userPrincipal.getName()));
		}
		
		return result;
	}
	
	private String getCurrentUser() {
		Principal userPrincipal = getThreadLocalRequest().getUserPrincipal();
		if (userPrincipal != null) {
			return userPrincipal.getName();
		} else {
			throw new Error("Please login");
		}
	}

	/* (non-Javadoc)
	 * @see com.gcgt.client.GreetingService#createNewChat(java.lang.String, java.lang.String)
	 */
	@Override
	public Chat createNewChat(String chatId) throws ChatAlreadyExists {
		Chat chat = getChatDao().get(chatId);
		if (chat != null) {
			throw new ChatAlreadyExists("Chat " + chatId + " already exists");
		}
		
		Chat result = new Chat(chatId, getCurrentUser());
		getChatDao().save(result);
		
		getChatService().invite(getCurrentUser(), chatId + Chat.SUFIX);
		
		return result;
	}
	
	/* (non-Javadoc)
	 * @see lt.vin.exaatto.client.service.RpcService#deleteChat(java.lang.String)
	 */
	@Override
	public void deleteChat(String chatId) throws NotOwnerException, NoSuchChatException {
		Chat chat = getChat(chatId);
		if (chat.getOwner().equalsIgnoreCase(getCurrentUser())) {
			getChatDao().delete(chatId);	
		} else {
			throw new NotOwnerException("Only owner can remove chat");
		}		
	}


	@Override
	public void addChatMember(String chatId, final String member) throws NotOwnerException, NoSuchChatException {
		new ChatUpdateTemplate(chatId) {
			
			@Override
			public void update(Chat chat) {
				chat.addMember(member);
			}
			
		}.update();
		
		getChatService().invite(member, chatId + Chat.SUFIX);
	}

	@Override
	public void addChatManager(String chatId, final String manager) throws NotOwnerException, NoSuchChatException {
		new ChatUpdateTemplate(chatId) {
			
			@Override
			public void update(Chat chat) {
				chat.addManager(manager);
			}
			
		}.update();
		
		getChatService().invite(manager, chatId + Chat.SUFIX);
	}

	/* (non-Javadoc)
	 * @see lt.vin.exaatto.client.service.RpcService#removeChatMember(java.lang.String, java.lang.String)
	 */
	@Override
	public void removeChatMember(String chatId, final String member) throws NotOwnerException, NoSuchChatException {
		new ChatUpdateTemplate(chatId) {
			
			@Override
			public void update(Chat chat) {
				chat.removeMember(member);
			}
			
		}.update();
	}

	/* (non-Javadoc)
	 * @see lt.vin.exaatto.client.service.RpcService#removeChatManager(java.lang.String, java.lang.String)
	 */
	@Override
	public void removeChatManager(String chatId, final String manager) throws NotOwnerException, NoSuchChatException {
		new ChatUpdateTemplate(chatId) {
			
			@Override
			public void update(Chat chat) {
				chat.removeManager(manager);
			}
			
		}.update();
	}
	
	abstract class ChatUpdateTemplate {

		private final String chatId;
		
		public ChatUpdateTemplate(String chatId) {
			this.chatId = chatId;
		}
		
		public abstract void update(Chat chat);
		
		public void update() throws NotOwnerException, NoSuchChatException {
			Chat chat = getChat(chatId);
			update(chat);
			getChatDao().save(chat);
		}
	}
	
	private Chat getChat(String chatId) throws NoSuchChatException, NotOwnerException {
		Chat chat = getChatDao().get(chatId);
		if (chat != null) {
			if (!chat.isManager(getCurrentUser())) {
				throw new NotOwnerException("Should be manager");
			}
		} else {
			throw new NoSuchChatException(chatId);
		}		
		
		return chat;
	}
	
	/**
	 * @return the chatDao
	 */
	public ChatDao getChatDao() {
		return chatDao;
	}

	/**
	 * @param chatDao the chatDao to set
	 */
	public void setChatDao(ChatDao chatDao) {
		this.chatDao = chatDao;
	}

	/**
	 * @return the chatService
	 */
	public ChatService getChatService() {
		return chatService;
	}

	/**
	 * @param chatService the chatService to set
	 */
	public void setChatService(ChatService chatService) {
		this.chatService = chatService;
	}
	
	
}
